package com.tinytoon.hunghoaqua;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class Panel extends SurfaceView implements SurfaceHolder.Callback {
	public static final int MODE_READY = 0;
	public static final int MODE_RUNING = 1;
	public int mMode = MODE_READY;

	public boolean playerWin = false;
	public int LEVEL_TIME;// seconds
	private int LEVEL_REQUIRE_SCORE;
	private long TIME_START_GAME;
	private long TIME_GENERATE_FRUITS;
	private long TIME_SHOWING_MESSAGE = 0;
	public int GAME_LEVEL = 1;

	public int mPlayerScore;
	public int mLastPLayerScore;
	public static float mWidth;
	public static float mHeight;
	public float speedX = 1;
	public float speedY = 1;

	private ViewThread mThread;
	private ArrayList<Element> mElements = new ArrayList<Element>();
	private ArrayList<Element> scoreList = new ArrayList<Element>();
	private int[] levelRequireScore = { 0, 50, 100, 150, 200, 250, 300, 350,
			400, 450,500, 550, 600, 650, 700, 750 };
	private HashMap<String, Integer> mapCharsAndProbabilities = new HashMap<String, Integer>();

	private Paint mPaint = new Paint();
	public Mario mMario;
	public Ball mBall;
	public Bitmap previousMarioState;
	public Bitmap background;


	public Panel(Context context, AttributeSet attr) {
		super(context, attr);
		setMode(MODE_READY);

		// after add callback, call surfaceCreate
		getHolder().addCallback(this);
		mThread = new ViewThread(this);

		// set paint property
		mPaint.setTextSize(dp2pixel(18));
		mPaint.setAntiAlias(true);

	}

	public void doDraw(long elapsed, Canvas canvas) {
		// draw background
		canvas.drawColor(Color.GRAY);
		if (background != null)
			canvas.drawBitmap(background, 0, 0, null);
		// draw normal fruits
		synchronized (mElements) {
			scoreList.clear();
			Iterator<Element> it = mElements.iterator();
			while (it.hasNext()) {
				Element tmp = it.next();
				if (tmp.mType != Element.TYPE_SCORE_MINUS
						&& tmp.mType != Element.TYPE_SCORE_PLUS) {
					tmp.doDraw(canvas);
				} else {
					scoreList.add(tmp);
				}
			}

			// then draw minus and plus icons
			if (!scoreList.isEmpty()) {
				it = scoreList.iterator();
				while (it.hasNext()) {
					it.next().doDraw(canvas);
				}
			}
		}

		mMario.doDraw(canvas);
		if (mBall != null)
			mBall.doDraw(canvas);

		// draw header
		mPaint.setColor(Color.GRAY);
		canvas.drawRect(0, 0, mWidth, dp2pixel(30), mPaint);

		// draw line
		mPaint.setColor(Color.BLUE);
		canvas.drawLine(0, dp2pixel(30), mWidth, dp2pixel(30), mPaint);

		// draw level
		mPaint.setColor(Color.YELLOW);
		mPaint.setTextAlign(Align.LEFT);
		canvas.drawText("Bài " + GAME_LEVEL, 0, dp2pixel(24), mPaint);// align
																		// top =
																		// (24-18)dp

		// draw player score
		mPaint.setTextAlign(Align.CENTER);
		canvas.drawText("Tổng điểm:" + mPlayerScore, mWidth / 2, dp2pixel(24),
				mPaint);

		// Draw current time
		if (!playerWin) {
			mPaint.setTextAlign(Align.RIGHT);
			canvas.drawText("" + getCurrentTime() + "/" + LEVEL_TIME, mWidth,
					dp2pixel(24), mPaint);
		} else {
			mPaint.setTextAlign(Align.RIGHT);
			canvas.drawText("" + LEVEL_TIME + "/" + LEVEL_TIME, mWidth,
					dp2pixel(24), mPaint);
			// Draw message
			if (TIME_SHOWING_MESSAGE <= 100) {
				drawWinMessage(canvas);
				TIME_SHOWING_MESSAGE++;
			} else {
				// after showing message, init new level
				TIME_SHOWING_MESSAGE = 0;
				initNewGame(++GAME_LEVEL);
			}
		}

	}

	private void drawWinMessage(Canvas canvas) {

		// get text bound
		mPaint.setTextAlign(Align.CENTER);
		String text = "Muc tieu bai 10 la 100 diem";
		Rect rect = new Rect();
		mPaint.getTextBounds(text, 0, text.length(), rect);

		// move to center
		float left = mWidth / 2 - (rect.width() / 2);
		float right = left + rect.width();
		float top = mHeight / 2 - (rect.height() / 2);
		float bottom = top + rect.height();
		// increase size
		left -= dp2pixel(5);
		top -= dp2pixel(18 + 5 + 12);// rect.height() * 4;
		right += dp2pixel(5);
		bottom += dp2pixel(18 + 5);// rect.height() * 4;

		// make blue border
		mPaint.setColor(Color.BLUE);
		canvas.drawRect(left, top, right, bottom, mPaint);

		// draw yellow background
		mPaint.setColor(Color.YELLOW);
		canvas.drawRect(left + 2, top + 2, right - 2, bottom - 2, mPaint);

		// draw text
		mPaint.setColor(Color.RED);
		canvas.drawText("Chúc mừng bạn", mWidth / 2,
				mHeight / 2 - dp2pixel(20), mPaint);
		canvas.drawText("Đã hoàn thành bài " + GAME_LEVEL, mWidth / 2,
				mHeight / 2, mPaint);
		int requireScore = 5000;
		if (GAME_LEVEL <= 15)
			requireScore = levelRequireScore[GAME_LEVEL + 1];
		canvas.drawText("Mục tiêu bài " + Integer.toString(GAME_LEVEL + 1)
				+ " là " + requireScore + " điểm", mWidth / 2, mHeight / 2
				+ dp2pixel(20), mPaint);
	}

	// @Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		mWidth = width;
		mHeight = height;
		mMario.mX = mWidth / 2;
		mMario.mY = mHeight - mMario.mBitmap.getHeight() - dp2pixel(20);
		mMario.mY_onGround = mMario.mY;
		mMario.mMovingDistance = (mWidth - mMario.mBitmap.getWidth())
				/ GameActivity.MAX_RANGE;
		Bitmap tmp = GameRes.getBitmap(getResources(), "background");

		float scaleY = (float) tmp.getHeight() / height;
		float scaleX = (float) tmp.getWidth() / width;
		int newWidth = Math.round(tmp.getWidth() / scaleX);
		int newHeight = Math.round(tmp.getHeight() / scaleY);
		background = Bitmap.createScaledBitmap(tmp, newWidth, newHeight, true);
	}

	// @Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (!mThread.isAlive()) {
			mMario = new Mario(getResources());
			// mBall = new Ball(getResources());
			mThread = new ViewThread(this);
			mThread.start();
		}
	}

	// @Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		if (mThread.isAlive()) {
			// mThread.setRunning(false);
			boolean retry = true;
			mMode = MODE_READY;
			while (retry) {
				try {
					mThread.join();
					retry = false;
				} catch (InterruptedException e) {
				}
			}
		}
	}

	// doLogic
	public void doLogic(long elapsedTime) {
		if (playerWin)
			return;

		checkTimeLeft();

		// Move
		mMario.animate();
		if (mBall != null)
			mBall.animate();
		fruitsMove();

		// Handle collision Mario-fruits and Mario-ball
		checkCollision();
		handleCollision();

		// Generate new fruits and ball
		generateFruits();
		generateBall();

		// Remove out of screen and finished animation icon
		removeFruits();
		removeBall();
	}

	public void checkTimeLeft() {
		if (getCurrentTime() >= LEVEL_TIME) {
			if (mPlayerScore >= LEVEL_REQUIRE_SCORE) {
				playerWin = true;
				mLastPLayerScore = mPlayerScore;

			} else {
				playerWin = false;
				Activity gameAct = (Activity) getContext();
				Intent in = new Intent(gameAct, GameOverActivity.class);
				in.putExtra("playerScore", mPlayerScore);
				in.putExtra("GAME_LEVEL", GAME_LEVEL);
				gameAct.startActivityForResult(in, 1);
				mMode = MODE_READY;
			}
		}
	}

	public void fruitsMove() {
		synchronized (mElements) {
			Iterator<Element> itor = mElements.iterator();
			while (itor.hasNext()) {
				itor.next().animate();
			}
		}
	}

	public void handleCollision() {
		synchronized (mElements) {
			Iterator<Element> it = mElements.iterator();
			ArrayList<Element> minusBitmaps = new ArrayList<Element>();
			while (it.hasNext()) {
				Element tmp = it.next();
				// touch correct, or touch on box have same animation
				if (tmp.mType == Element.TYPE_SCORE_PLUS) {
					doScorePlusAnimate(tmp, it);
				} else if (tmp.mType == Element.TYPE_RED_BORDER) {
					doScoreMinusAnimate(tmp, it);
				} else if (tmp.mType == Element.TYPE_BOX_PLUS_4) {
					doPlusAnimation(tmp, it, 4);
				} else if (tmp.mType == Element.TYPE_BOX_PLUS_3) {
					doPlusAnimation(tmp, it, 3);
				} else if (tmp.mType == Element.TYPE_BOX_PLUS_2) {
					doPlusAnimation(tmp, it, 2);
				} else if (tmp.mType == Element.TYPE_BOX_PLUS_1) {
					doPlusAnimation(tmp, it, 1);
				} else if (tmp.mType == Element.TYPE_TIME_PLUS_5) {
					doPlusAnimation(tmp, it, 5);
				} else if (tmp.mType == Element.TYPE_TIME_PLUS_10) {
					doPlusAnimation(tmp, it, 10);
				} else if (tmp.mType == Element.TYPE_TIME_PLUS_20) {
					doPlusAnimation(tmp, it, 20);
				}
			}// end while

			// Mario hits ball
			if (mMario.mType == Mario.TYPE_HIT_BALL) {
				doScoreMinusMario(minusBitmaps);
			}

			// score minus
			mElements.addAll(minusBitmaps);
			// animate minus score
			it = mElements.iterator();
			while (it.hasNext()) {
				Element tmp = it.next();
				if (tmp.mType == Element.TYPE_SCORE_MINUS) {
					switch (tmp.mAnimatioStep) {
					// 6 steps animation
					case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 6):
						tmp.mType = Element.TYPE_FINISH_ANIMATION;
						break;
					default:
						tmp.mY -= tmp.getmBitmap().getHeight() / 10;
						break;
					}
					tmp.mAnimatioStep++;
				}
			}

		}
	}

	public void doPlusAnimation(Element tmp, Iterator<Element> it, int type) {
		switch (tmp.mAnimatioStep) {
		// make icon brighter
		case Element.STEP_ANIMATION_START:
			Bitmap firstStep = tmp.blurBitmap(Color.YELLOW); //
			tmp.setmBitmap(firstStep);
			break;
		// icon backs to normal state
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL):
			tmp.setmBitmap(GameRes.getBitmap(getResources(), tmp.getChar()));
			break;
		// brighter again
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 2):
			Bitmap thirthStep = tmp.blurBitmap(Color.YELLOW);
			tmp.setmBitmap(thirthStep);
			break;
		// normal state
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 3):
			tmp.setmBitmap(GameRes.getBitmap(getResources(), tmp.getChar()));
			break;
		// change icon
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 4):
			if (type == 4)
				tmp.setmBitmap(GameRes.getBitmap(getResources(), "plus 50"));
			else if (type == 3)
				tmp.setmBitmap(GameRes.getBitmap(getResources(), "plus 20"));
			else if (type == 2)
				tmp.setmBitmap(GameRes.getBitmap(getResources(), "plus 10"));
			else if (type == 1)
				tmp.setmBitmap(GameRes.getBitmap(getResources(), "plus 5"));
			else if (type == 5)
				tmp.setmBitmap(GameRes.getBitmap(getResources(), "plus time 5"));
			else if (type == 10)
				tmp.setmBitmap(GameRes
						.getBitmap(getResources(), "plus time 10"));
			else if (type == 20)
				tmp.setmBitmap(GameRes
						.getBitmap(getResources(), "plus time 20"));
			break;
		// finish animation
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 6):
			tmp.mType = Element.TYPE_FINISH_ANIMATION;
			it.remove();
			break;
		default:
			tmp.mY -= dp2pixel(5);
			break;
		}

		tmp.mAnimatioStep++;
	}

	public void doScoreMinusMario(ArrayList<Element> minusBitmaps) {
		switch (mMario.mAnimatioStep) {
		// make red border around icon
		case Mario.STEP_ANIMATION_START:
			previousMarioState = mMario.mBitmap;
			mMario.mBitmap = mMario.blurBitmap();
			break;
		// icon backs to normal state
		case (Mario.STEP_ANIMATION_START + Mario.STEP_ANIMATION_INTERVAL):
			mMario.mBitmap = previousMarioState;
			break;
		// make read border again
		case (Mario.STEP_ANIMATION_START + Mario.STEP_ANIMATION_INTERVAL * 2):
			mMario.mBitmap = mMario.blurBitmap();

			// then add "score minus", add -3 icon
			Element minusElm = new Element(getResources(), "score minus", 0, 0);
			minusElm.mX = mMario.mX;
			minusElm.mY = mMario.mY;
			minusElm.mType = Element.TYPE_SCORE_MINUS;
			mPlayerScore -= 3;

			minusBitmaps.add(minusElm);
			break;
		// back to normal state
		case (Mario.STEP_ANIMATION_START + Mario.STEP_ANIMATION_INTERVAL * 3):
			mMario.mBitmap = previousMarioState;
			break;
		// make red border around icon
		case (Mario.STEP_ANIMATION_START + Mario.STEP_ANIMATION_INTERVAL * 4):
			mMario.mBitmap = mMario.blurBitmap();
			break;
		// icon backs to normal state
		case (Mario.STEP_ANIMATION_START + Mario.STEP_ANIMATION_INTERVAL * 5):
			mMario.mBitmap = previousMarioState;
			break;
		// finish animation
		case (Mario.STEP_ANIMATION_START + Mario.STEP_ANIMATION_INTERVAL * 6):
			mMario.mType = Mario.TYPE_NORMAL;
			if (mMario.mSpeedY < 0)
				mMario.mStatus = Mario.JUMP_UP;
			else if (mMario.mSpeedY > 0)
				mMario.mStatus = Mario.FALL_DOWN;
			else {
				mMario.mY = mMario.mY_onGround;
				mMario.mStatus = Mario.STANDING;
			}
			getHandler().post(new Runnable() {
				public void run() {
					GameActivity.sb.setEnabled(true);
				}
			});
			break;
		default:
			break;
		}

		mMario.mAnimatioStep++;
	}

	public void doScoreMinusAnimate(Element tmp, Iterator<Element> it) {
		switch (tmp.mAnimatioStep) {
		// make red border around icon
		case Element.STEP_ANIMATION_START:
			Bitmap firstStep = tmp.blurBitmap(Color.RED);
			tmp.setmBitmap(firstStep);
			break;
		// icon backs to normal state
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL):
			tmp.setmBitmap(GameRes.getBitmap(getResources(), tmp.getChar()));
			break;
		// make read border again
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 2):
			Bitmap thirthStep = tmp.blurBitmap(Color.RED);
			tmp.setmBitmap(thirthStep);
			break;
		// back to normal state
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 3):
			tmp.setmBitmap(GameRes.getBitmap(getResources(), tmp.getChar()));
			break;
		// change icon to "score minus"
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 4):
			tmp.setmBitmap(GameRes.getBitmap(getResources(), "score minus"));
			break;
		// finish animation
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 8):
			tmp.mType = Element.TYPE_FINISH_ANIMATION;
			it.remove();
			break;
		default:
			tmp.mY -= dp2pixel(5);
			break;
		}

		tmp.mAnimatioStep++;
	}

	public void doScorePlusAnimate(Element tmp, Iterator<Element> it) {
		switch (tmp.mAnimatioStep) {
		// make icon brighter
		case Element.STEP_ANIMATION_START:
			Bitmap firstStep = tmp.blurBitmap(Color.WHITE);
			tmp.setmBitmap(firstStep);
			break;
		// icon backs to normal state
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL):
			tmp.setmBitmap(GameRes.getBitmap(getResources(), tmp.getChar()));
			break;
		// brighter again
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 2):
			Bitmap thirthStep = tmp.blurBitmap(Color.WHITE);
			tmp.setmBitmap(thirthStep);
			break;
		// normal state
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 3):
			tmp.setmBitmap(GameRes.getBitmap(getResources(), tmp.getChar()));
			break;
		// change icon to "score plus"
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 4):
			tmp.setmBitmap(GameRes.getBitmap(getResources(), "score plus"));
			break;
		// finish animation
		case (Element.STEP_ANIMATION_START + Element.STEP_ANIMATION_INTERVAL * 8):
			tmp.mType = Element.TYPE_FINISH_ANIMATION;
			it.remove();
			break;
		default:
			tmp.mY -= dp2pixel(5);
			// Log.d("tmp.mY","=="+tmp.mY);
			break;
		}

		tmp.mAnimatioStep++;
	}

	public void checkCollision() {
		// check collision between MArio and ball
		if (mBall != null) {
			if (Mario.checkCollision(mBall.getRect(), mMario.getRect())
					&& mMario.mType == Mario.TYPE_NORMAL) {
				// Disable seekbar
				getHandler().post(new Runnable() {

					public void run() {
						GameActivity.sb.setEnabled(false);
					}
				});
				mMario.mType = Mario.TYPE_HIT_BALL;
				mMario.mAnimatioStep = Mario.STEP_ANIMATION_START;
				mMario.mStatus = Mario.HIT_BALL;
				mMario.mSpeedX = 0;
				mMario.mSpeedY = 0;
			}
		}

		// check collision between Mario and fruits
		synchronized (mElements) {
			int n = mElements.size() - 1;
			while (n >= 0) {
				Element tmp = mElements.get(n);
				if (tmp.mType == Element.TYPE_NORMAL) {
					if (Mario.checkCollision(tmp.getRect(),
							mMario.getHeadRect())) {
						tmp.mSpeedX = 0;
						tmp.mSpeedY = 0;

						if (tmp.getChar().equals("box plus 4")) {
							tmp.mType = Element.TYPE_BOX_PLUS_4;
							tmp.mAnimatioStep = Element.STEP_ANIMATION_START;
							mPlayerScore += 50;
							break;
						} else if (tmp.getChar().equals("box plus 3")) {
							tmp.mType = Element.TYPE_BOX_PLUS_3;
							tmp.mAnimatioStep = Element.STEP_ANIMATION_START;
							mPlayerScore += 20;
							break;
						} else if (tmp.getChar().equals("box plus 2")) {
							tmp.mType = Element.TYPE_BOX_PLUS_2;
							tmp.mAnimatioStep = Element.STEP_ANIMATION_START;
							mPlayerScore += 10;
							break;
						} else if (tmp.getChar().equals("box plus 1")) {
							tmp.mType = Element.TYPE_BOX_PLUS_1;
							tmp.mAnimatioStep = Element.STEP_ANIMATION_START;
							mPlayerScore += 5;
							break;
						} else if (tmp.getChar().equals("box time 5")) {
							tmp.mType = Element.TYPE_TIME_PLUS_5;
							tmp.mAnimatioStep = Element.STEP_ANIMATION_START;
							LEVEL_TIME += 5;
							break;
						} else if (tmp.getChar().equals("box time 10")) {
							tmp.mType = Element.TYPE_TIME_PLUS_10;
							tmp.mAnimatioStep = Element.STEP_ANIMATION_START;
							LEVEL_TIME += 10;
							break;
						} else if (tmp.getChar().equals("box time 20")) {
							tmp.mType = Element.TYPE_TIME_PLUS_20;
							tmp.mAnimatioStep = Element.STEP_ANIMATION_START;
							LEVEL_TIME += 20;
							break;
						} else if (tmp.getChar().equals("box bomb")) {
							// exploding all boxes
							// change boxes to TYPE_SCORE_PLUS, so all boxes
							// start exploision and +5
							explodeAllIcons();
						}

						if (tmp.isFruits()) {
							tmp.mType = Element.TYPE_SCORE_PLUS;
							tmp.mAnimatioStep = Element.STEP_ANIMATION_START;
							mPlayerScore += 5;
							break;
						} else {
							tmp.mType = Element.TYPE_RED_BORDER;
							tmp.mAnimatioStep = Element.STEP_ANIMATION_START;
							break;
						}
					}
				}
				n--;
			}
		}
	}

	public void explodeAllIcons() {
		synchronized (mElements) {
			Iterator<Element> it = mElements.iterator();
			while (it.hasNext()) {
				Element tmp = it.next();
				tmp.mType = Element.TYPE_SCORE_PLUS;
				tmp.mSpeedY = 0;
				mPlayerScore += 5;
			}
		}
	}

	public void generateBall() {
		int now = getCurrentTime();
		if (now % 17 == 0 && now > 10) {
			if (mBall == null)
				mBall = new Ball(getResources());
		}
	}

	public void generateFruits() {
		synchronized (mElements) {
			long now = System.currentTimeMillis();
			long interval = 2800 - 300 * GAME_LEVEL;
			if (interval < 400)
				interval = 400;
			switch (GAME_LEVEL) {
			case 1:
				if ((now - TIME_GENERATE_FRUITS) >= interval || mElements.isEmpty()) {
					mapCharsAndProbabilities.clear();
					mapCharsAndProbabilities.put("peach", 65);
					mapCharsAndProbabilities.put("ananas", 65);
					mapCharsAndProbabilities.put("apple1", 60);
					mapCharsAndProbabilities.put("apricot", 55);
					mapCharsAndProbabilities.put("banana1", 65);
					mapCharsAndProbabilities.put("cherry1", 60);
					mapCharsAndProbabilities.put("grape", 60);
					mapCharsAndProbabilities.put("kiwi", 50);
					mapCharsAndProbabilities.put("lemon1", 50);
					mapCharsAndProbabilities.put("lime", 50);
					mapCharsAndProbabilities.put("mango", 50);
					mapCharsAndProbabilities.put("maracuja", 55);
					mapCharsAndProbabilities.put("strawberry1", 50);
					mapCharsAndProbabilities.put("watermelon2", 60);
					
					mapCharsAndProbabilities.put("shoe3", 60);
					mapCharsAndProbabilities.put("shoe2", 60);
					mapCharsAndProbabilities.put("shoe1", 60);
					mapCharsAndProbabilities.put("cake", 60);

					mapCharsAndProbabilities.put("box bomb", 5);
					mapCharsAndProbabilities.put("box plus 4", 1);
					mapCharsAndProbabilities.put("box plus 2", 2);
					mapCharsAndProbabilities.put("box plus 3", 1);
					mapCharsAndProbabilities.put("box plus 1", 2);
					mapCharsAndProbabilities.put("box time 5", 2);
					mapCharsAndProbabilities.put("box time 10", 1);
					mapCharsAndProbabilities.put("box time 20", 1);

					String nextChar = autoGenerateChar(mapCharsAndProbabilities);
					setSpeed(GAME_LEVEL);
					mElements.add(new Element(getResources(), nextChar, speedX,
							speedY));

					TIME_GENERATE_FRUITS = now;
				}
				break;
			default:
				if ((now - TIME_GENERATE_FRUITS) >= interval || mElements.isEmpty()) {
					mapCharsAndProbabilities.clear();
					mapCharsAndProbabilities.put("peach", 30);
					mapCharsAndProbabilities.put("ananas", 30);
					mapCharsAndProbabilities.put("apple1", 30);
					mapCharsAndProbabilities.put("apple2", 30);
					mapCharsAndProbabilities.put("apricot", 30);
					mapCharsAndProbabilities.put("banana1", 30);
					mapCharsAndProbabilities.put("banana2", 30);
					mapCharsAndProbabilities.put("banana3", 30);
					mapCharsAndProbabilities.put("cherry1", 30);
					mapCharsAndProbabilities.put("cherry2", 30);
					mapCharsAndProbabilities.put("fruits", 30);
					mapCharsAndProbabilities.put("grape", 30);
					mapCharsAndProbabilities.put("kiwi", 30);
					mapCharsAndProbabilities.put("lemon1", 30);
					mapCharsAndProbabilities.put("lemon2", 30);
					mapCharsAndProbabilities.put("lime", 30);
					mapCharsAndProbabilities.put("mango", 30);
					mapCharsAndProbabilities.put("maracuja", 40);
					mapCharsAndProbabilities.put("strawberry1", 40);
					mapCharsAndProbabilities.put("strawberry2", 40);
					mapCharsAndProbabilities.put("strawberry3", 40);
					mapCharsAndProbabilities.put("strawberry4", 30);
					mapCharsAndProbabilities.put("strawberry5", 30);
					mapCharsAndProbabilities.put("watermelon1", 30);
					mapCharsAndProbabilities.put("watermelon2", 30);

					mapCharsAndProbabilities.put("shoe2", 50);
					mapCharsAndProbabilities.put("shoe3", 46);
					mapCharsAndProbabilities.put("shoe1", 50);
					mapCharsAndProbabilities.put("cake", 50);

					mapCharsAndProbabilities.put("box bomb", 5);
					mapCharsAndProbabilities.put("box plus 4", 1);
					mapCharsAndProbabilities.put("box plus 2", 1);
					mapCharsAndProbabilities.put("box plus 3", 1);
					mapCharsAndProbabilities.put("box plus 1", 2);
					mapCharsAndProbabilities.put("box time 5", 2);
					mapCharsAndProbabilities.put("box time 10", 1);
					mapCharsAndProbabilities.put("box time 20", 1);

					String nextChar = autoGenerateChar(mapCharsAndProbabilities);
					setSpeed(GAME_LEVEL);
					mElements.add(new Element(getResources(), nextChar, speedX,
							speedY));
					
					TIME_GENERATE_FRUITS = now;
				}
				break;
			}
		}
	}

	// 2.6 Remove out of screen and already finish animation icons
	public void removeFruits() {
		synchronized (mElements) {
			Iterator<Element> it = mElements.iterator();
			while (it.hasNext()) {
				Element tmp = it.next();
				if (tmp.isOutOfScreen()
						|| tmp.mType == Element.TYPE_FINISH_ANIMATION) {
					it.remove();
				}
			}
		}
	}

	public void removeBall() {
		if (mBall != null) {
			if (mBall.isOutOfScreen()) {
				Log.d("remove ball", "====ball is out of screen");
				mBall = null;
			}
		}
	}

	// Generate char base on its probability
	// chars[]={a, b, c, d, e} 
	// prob[] ={600, 100, 100, 100, 100}
	public String autoGenerateChar(HashMap<String, Integer> map) {
		ArrayList<String> chars = new ArrayList<String>(map.keySet());
		ArrayList<Integer> probabilities = new ArrayList<Integer>(map.values());
		String result = null;
		Random r = new Random();
		int number = r.nextInt(1000);
		int leftRange = 0;
		int rightRange = probabilities.get(0);
		for (int i = 0; i < chars.size(); i++) {
			if ((number >= leftRange) && (number < rightRange)) {
				return chars.get(i);
			}
			leftRange = rightRange;
			rightRange = rightRange + probabilities.get(i + 1);
		}
		return result;
	}

	// Get current playing time, in second
	private int getCurrentTime() {
		return (int) (System.currentTimeMillis() - TIME_START_GAME) / 1000;
	}

	public void setMode(int newMode) {
		mMode = newMode;
		switch (newMode) {
		case MODE_READY:
			initNewGame(GAME_LEVEL);
			mMode = MODE_RUNING;
			break;
		case MODE_RUNING:
			mMode = MODE_RUNING;
			break;
		default:
			break;
		}
	}

	private void initNewGame(int level) {
		long now = System.currentTimeMillis();
		TIME_START_GAME = now;
		TIME_GENERATE_FRUITS = now;
		playerWin = false;
		mElements.clear();
		setSpeed(level);
		Handler handler = getHandler();
		if (handler != null) {
			handler.post(new Runnable() {

				public void run() {
					GameActivity.sb.setEnabled(true);
				}
			});
		}
		mBall = null;

		switch (level) {
		case 1:
			mPlayerScore = 0;
			LEVEL_TIME = 60;
			LEVEL_REQUIRE_SCORE = levelRequireScore[level];
			break;

		case 2:
			LEVEL_TIME = 60;
			LEVEL_REQUIRE_SCORE = levelRequireScore[level];
			mMode = MODE_RUNING;
			break;

		default:
			LEVEL_TIME = 60;
			if (level >= 16)
				LEVEL_REQUIRE_SCORE = 5000;
			LEVEL_REQUIRE_SCORE = levelRequireScore[level];
			mMode = MODE_RUNING;
			break;
		}
	}

	private void setSpeed(int level) {
		float speedY_Lv1 = 1f;
		float speedY_increase = 0.8f;
		speedY = (level - 1) * speedY_increase + speedY_Lv1;
		speedX = 0;
	}

	public int dp2pixel(int dp) {
		int pixel = (int) TypedValue.applyDimension(
				TypedValue.COMPLEX_UNIT_DIP, dp, getResources()
						.getDisplayMetrics());
		return pixel;
	}
}
